﻿//using System;
//using System.Collections.Generic;
//using ArgusPCLib.BitRepresentations;

//namespace ArgusPCLib.Mathematics
//{
//	public class Float
//	{
//		#region Static
//		#region Fields
//		const int ExponentMask = (int)(~0u >> 1);
//		const int ExponentBias = ExponentMask >> 1;
//		public const int MaxExponent = ExponentBias;
//		public const int MinExponent = 1-ExponentBias;
//		public const int Base = ~0;
//		#endregion

//		#region Properties
//		public static int WordSize { get { return BitManager.WordSize; } }

//		public static NaNTypes ExceptionThrowingNaNs { get; set; }
//		#endregion

//		#region Constructors
//		static Float()
//		{

//		}
//		#endregion

//		#region Methods
//		#region Various
//		public static bool IsNan(Float f) { return f.isNan; }
//		public static bool IsInfinity(Float f) { return f.isInfinity; }
//		public static bool IsPositiveInfinity(Float f) { return f.isPositiveInfinity; }
//		public static bool IsNegativeInfinity(Float f) { return f.isNegativeInfinity; }
//		public static bool GetSign(Float f) { return f.isNegative; }
//		public static WordCollection GetSignificant(Float f) { return new WordCollection(f); }
//		public static BitCollection GetSignificantBits(Float f) { return new BitCollection(f); }
//		public static int GetExponent(Float f) { return f.exponent; }

//		public static Exception GetExceptionFromNaN(Float nan)
//		{
//			return Float.GetExceptionFromNaN(nan.NaNType);
//		}

//		public static Exception GetExceptionFromNaN(NaNTypes nanType)
//		{
//			if (nanType.HasFlag(NaNTypes.Overflow))
//				return new OverflowException();
//			if (nanType.HasFlag(NaNTypes.DividedByZero))
//				return new DivideByZeroException();
//			if (nanType.HasFlag(NaNTypes.InvalidArgument))
//				return new ArgumentException("An operation with at least one invalid argument was attempted, e.g. sqrt(x) where x < 0.");
//			if (nanType.HasFlag(NaNTypes.OperationWithNaNArg))
//				return new InvalidOperationException("An operation with at least one argument being a NaN was ettempted.");
//			if (nanType.HasFlag(NaNTypes.Unkown))
//				return new Exception("Unkown");
//			return null;
//		}

//		public static void ThrowExceptionFromNaN(Float nan)
//		{
//			Float.ThrowExceptionFromNaN(nan.NaNType);
//		}

//		public static void ThrowExceptionFromNaN(NaNTypes nanType)
//		{
//			Exception exception = Float.GetExceptionFromNaN(nanType);
//			if (exception != null)
//				throw exception;
//		}
//		#endregion

//		#region Math
//		public static Float Negate(Float f)
//		{
//			Float RetVal = new Float(f);
//			RetVal.isNegative = !f.isNegative;
//			return RetVal;
//		}
//		#endregion

//		#region Operators
//		#region Comparison
//		public static bool operator ==(Float a, Float b)
//		{
//			if (object.ReferenceEquals(a, null) || object.ReferenceEquals(b, null))
//				return object.ReferenceEquals(a, b);

//			if (a.uExponent == 0 && b.uExponent == 0)
//				return true;
//			if (a.isInfinity && b.isInfinity)
//				return a.isNegative == b.isNegative;
//			if (a.isNan || b.isNan)
//				return a.isNan == b.isNan;
//			if (a.isNegative != b.isNegative)
//				return false;
//			return a.bitManager == b.bitManager;
//		}

//		public static bool operator !=(Float a, Float b)
//		{
//			return !(a == b);
//		}

//		public static bool operator <(Float a, Float b)
//		{
//			if (a.isNan || b.isNan)
//				throw new InvalidOperationException("Cannot compare NaN's");

//			if (a.uExponent == 0 && b.uExponent == 0)
//				return false;
//			if (a.isNegative != b.isNegative)
//				return a.isNegative;
//			if (a.isInfinity && b.isInfinity)
//				return false;
//			if (a.isInfinity)
//				return a.isNegative;
//			if (b.isNegative)
//				return !a.isNegative;
//			if (a.exponent < b.exponent)
//				return !a.isNegative;
//			if (a.exponent > b.exponent)
//				return a.isNegative;

//			if (a.isNegative)
//				return a.bitManager > b.bitManager;
//			else
//				return a.bitManager < b.bitManager;
//		}

//		public static bool operator >(Float a, Float b)
//		{
//			if (a.isNan || b.isNan)
//				throw new InvalidOperationException("Cannot compare NaN's");

//			if (a.uExponent == 0 && b.uExponent == 0)
//				return false;
//			if (a.isNegative != b.isNegative)
//				return !a.isNegative;
//			if (a.isInfinity && b.isInfinity)
//				return false;
//			if (a.isInfinity)
//				return !a.isNegative;
//			if (b.isNegative)
//				return a.isNegative;
//			if (a.exponent < b.exponent)
//				return a.isNegative;
//			if (a.exponent > b.exponent)
//				return !a.isNegative;

//			if (a.isNegative)
//				return a.bitManager < b.bitManager;
//			else
//				return a.bitManager > b.bitManager;
//		}

//		public static bool operator <=(Float a, Float b)
//		{
//			return (a < b || a == b);
//		}

//		public static bool operator >=(Float a, Float b)
//		{
//			return (a > b || a == b);
//		}
//		#endregion

//		#region Math Operators
//		public static Float operator -(Float f) { return Float.Negate(f); }

//		public static Float operator +(Float a, Float b)
//		{
//			if (a.isNan || b.isNan)
//				return new Float(NaNTypes.OperationWithNaNArg);
//		}
//		#endregion
//		#endregion
//		#endregion
//		#endregion

//		#region Instance
//		#region Fields
//		BitManager bitManager;
//		int signAndExponent;
//		#endregion

//		#region Properties
//		bool isNegative
//		{
//			get { return ((uint)this.signAndExponent >> 31) == 1u; }
//			set
//			{
//				int mask = 1 << 31;
//				if (value == true)
//					this.signAndExponent |= mask;
//				else
//					this.signAndExponent &= ~mask;
//			}
//		}

//		int exponent
//		{
//			get { return this.uExponent-Float.ExponentBias; }
//			set { this.uExponent = value + Float.ExponentBias; }
//		}

//		int uExponent
//		{
//			get { return (this.signAndExponent & Float.ExponentMask); }
//			set { this.signAndExponent = (this.signAndExponent & ~Float.ExponentMask) | (value & Float.ExponentMask); }
//		}

//		bool isInfinity
//		{
//			get
//			{
//				if ((this.signAndExponent & Float.ExponentMask) != Float.ExponentMask)
//					return false;
//				return this.NaNType.HasFlag(NaNTypes.Infinity);
//			}
//		}

//		NaNTypes NaNType
//		{
//			get
//			{
//				if ((this.signAndExponent & Float.ExponentMask) != Float.ExponentMask)
//					return NaNTypes.None;
//				return (NaNTypes)this.bitManager[0];
//			}
//			set
//			{
//				this.signAndExponent |= Float.ExponentMask;
//				this.bitManager.Clear();
//				this.bitManager[0] = (int)value;
//				if (value != NaNTypes.None && (Float.ExceptionThrowingNaNs & value) == value)
//					Float.ThrowExceptionFromNaN(value);
//			}
//		}

//		bool isNan { get { return (this.NaNType != NaNTypes.None); } }
//		bool isPositiveInfinity { get { return this.isInfinity && !this.isNegative; } }
//		bool isNegativeInfinity { get { return this.isInfinity && this.isNegative; } }
//		#endregion

//		#region Constructors
//		Float(NaNTypes nanType)
//		{
//			this.bitManager = new BitManager(1);
//			this.NaNType = nanType;
//		}

//		Float(int signAndExponent, BitManager bitManager, bool normalize)
//		{
//			this.isNegative = isNegative;
//			if (bitManager == null)
//			{
//				this.bitManager = new BitManager();
//				this.isNegative = false;
//			}
//			else
//			{
//				this.bitManager = bitManager;
//				if (normalize)
//					this.Normalize();
//			}
//		}

//		Float(BitManager bitManager, bool normalize)
//			: this(0, bitManager, normalize) { }

//		public Float(IEnumerable<int> words, int exponent, bool isNegative)
//			: this(new BitManager(words), false)
//		{
//			this.isNegative = isNegative;
//			if (exponent < Float.MinExponent || exponent > Float.MaxExponent)
//				throw new ArgumentOutOfRangeException("exponent");
//			this.exponent = exponent;
//			this.Normalize();
//		}

//		public Float(IEnumerable<int> words)
//			: this(words, 0, false) { }

//		public Float(Float d)
//			: this(d.signAndExponent, new BitManager(d.bitManager), false) { }

//		public Float(int value)
//			: this(new BitManager(1), false)
//		{
//			if (value < 0)
//			{
//				this.isNegative = true;
//			}
//			if (value == int.MinValue)
//			{
//				this.bitManager[0] = int.MaxValue;
//				this.bitManager.Add(1);
//			}
//			else
//			{
//				this.bitManager[0] = System.Math.Abs(value);
//			}
//			this.exponent = this.bitManager.Length;
//			this.Normalize();
//		}

//		public Float(long value)
//			: this(new BitManager(2), false)
//		{
//			this.exponent = 0;
//			if (value < 0)
//			{
//				this.isNegative = true;
//			}
//			if (value == long.MinValue)
//			{
//				this.bitManager.Add(long.MaxValue);
//				this.bitManager.Add(1);
//			}
//			else
//			{
//				this.bitManager.Add(System.Math.Abs(value));
//			}
//			this.bitManager.Add(value);
//			this.exponent = this.bitManager.Length;
//			this.Normalize();
//		}

//		public Float(float f)
//			:this(0, new BitManager(), false)
//		{
//			if (float.IsNaN(f))
//			{
//				this.NaNType = NaNTypes.Unknown;
//			}
//			else
//			{
//				this.isNegative = f < 0;
//				if (float.IsInfinity(f))
//				{
//					this.isInfinity = true;
//				}
//				else if (f != 0f)
//				{
//					int fSig, fExp;
//					f.GetBits(out fSig, out fExp);

//					this.bitManager[0] = fSig;
//					this.exponent = 1;
//					int fractionBits = 23 - fExp;
//					if (fractionBits < 0)
//					{
//						this.exponent += -fractionBits / Float.WordSize+1;
//						this.bitManager.LLS(-fractionBits % Float.WordSize);
//					}
//					else if (fractionBits > 0)
//					{
//						this.exponent -= fractionBits / Float.WordSize;
//						this.bitManager.LLS(Float.WordSize - (fractionBits % Float.WordSize));
//					}

//					this.Normalize();
//				}
//			}
//		}

//		public Float(double d)
//			: this(0, new BitManager(0), false)
//		{
//			if (double.IsNaN(d))
//			{
//				this.NaNType = NaNTypes.Unknown;
//			}
//			else
//			{
//				this.isNegative = d < 0;
//				if (double.IsInfinity(d))
//				{
//					this.isInfinity = true;
//				}
//				else if (d != 0d)
//				{
//					long dSig;
//					int dExp;
//					d.GetBits(out dSig, out dExp);

//					this.bitManager.Add(dSig);
//					this.exponent = this.bitManager.Length;
//					int fractionBits = 52 - dExp;
//					if (fractionBits < 0)
//					{
//						this.exponent += -fractionBits / Float.WordSize + 1;
//						this.bitManager.LLS(-fractionBits % Float.WordSize);
//					}
//					else if (fractionBits > 0)
//					{
//						this.exponent -= fractionBits / Float.WordSize;
//						this.bitManager.LLS(Float.WordSize - (fractionBits % Float.WordSize));
//					}

//					this.Normalize();
//				}
//			}
//		}
//		#endregion

//		#region Methods
//		#region Private
//		void Normalize()
//		{
//			this.bitManager.TrimTrailingWords();
//			if (this.bitManager.Length == 0 && !this.isInfinity)
//			{
//				this.signAndExponent = 0;
//				return;
//			}
//			int count = this.bitManager.TrimLeadingWords();
//			count = this.exponent - count;
//			if (count < Float.MinExponent)
//				this.NaNType = NaNTypes.Overflow;
//			else
//				this.exponent = count;
//		}
//		#endregion
//		#endregion
//		#endregion

//		#region Subtypes
//		[Flags]
//		public enum NaNTypes : int
//		{
//			None = 0,
//			Infinity = 1,
//			/// <summary>
//			/// Result of an operation with at least one argument being a NaN,
//			/// e.g. the sum of a NaN and another value.
//			/// </summary>
//			OperationWithNaNArg = 1 << 1,
//			/// <summary>
//			/// Result is to big/small to be represented, e.g. the result of
//			/// the multiplication of to values where the sum of the exponent
//			/// of each value exceed <see cref="Float.MaxExponent"/>.
//			/// This flag will usually be used with <see cref="NaNTypes.Infinity"/>.
//			/// </summary>
//			Overflow = 1 << 2,
//			/// <summary>
//			/// Result of a divison by zero. Unless the dividend was also zero,
//			/// this flag will be paired with <see cref="NaNTypes.Infinity"/>.
//			/// </summary>
//			DividedByZero = 1 << 3,
//			/// <summary>
//			/// Result of an operation with an invalid argument, e.g. sqrt(x) with x < 0
//			/// or log(x) with x <= 0.
//			/// </summary>
//			InvalidArgument = 1 << 4,
//			Unkown = 1 << 31
//		}

//		public class WordCollection : IntIndexedPropertyGet<int>
//		{
//			Float f;

//			public WordCollection(Float f)
//			{
//				if (f == null)
//					throw new ArgumentNullException();
//				this.f = f;
//			}

//			public override int Count { get { return this.f.bitManager.Length; } }
//			public override int this[int index] { get { return this.f.bitManager[index]; } }
//		}

//		public class BitCollection : IntIndexedPropertyGet<bool>
//		{
//			Float f;

//			public BitCollection(Float f)
//			{
//				if (f == null)
//					throw new ArgumentNullException();
//				this.f = f;
//			}

//			public override int Count { get { return this.f.bitManager.BitLength; } }
//			public override bool this[int index] { get { return this.f.bitManager.Bits[index]; } }
//		}
//		#endregion
//	}
//}
